
import {EasyA} from "../common/EasyA";
import {Controller} from "./Controller";
import {UtilFile} from "../util/UtilFile";
import {Log} from "../util/Log";
import {EasyACtx} from "./EasyACtx";
import {Action} from "./Action";
import {_} from "../util/UtilTs";
import {Interceptor} from "./Interceptor";


export class EasyARouter{
    private framework:EasyA;

    constructor(
        EasyAFramework:EasyA,
        public registerActionStrategy:IRegisterActionStrategy = new RegisterActionWithExpressNext()
    )
    {
        this.framework = EasyAFramework;

    }

    //注册 控制器类
    registerController(controller:Controller){
        const frameWork = this.framework;

        const actions = controller.getActions();
        EasyA.controllers.push(controller);

        _.each(actions,(action:Action)=>{
            action.associatedProps.routePath = `/${controller.routePath}/${action.route }`;
            //消除连续的 / 字符
            action.associatedProps.routePath = _.replace(action.associatedProps.routePath, /[/]+/g, '/');

            action.associatedProps.interceptors = Controller.reorganizeInterceptor(_.concat(
                this.framework.interceptors,
                controller.interceptors,
                action.interceptors,
            ));
            const handles = Interceptor.getHandlesFromFlowInterceptors(action.associatedProps.interceptors);


            //最终的，一个url对应的所有处理器
            action.associatedProps.handles = _.concat(
                handles.beforeHandles,
                action,
                _.reverse(handles.afterHandles),
            );
            this.registerAction(action);
        });

    }


    private registerAction(action:Action){
        Log.info(`
注册路由:${action.name}
路由地址:${action.associatedProps.routePath}
`);
        this.registerActionStrategy.register(this.framework,action);
    }


    registerAllController(){

        const webRoot = this.framework.setting.rootDir;
        const staticDir = this.framework.setting.staticDir;

        UtilFile.listFile(webRoot,(file)=> {

            if(file.dir.indexOf(staticDir)<0){ //排除静态文件夹
                //扫描所有js 文件
                if(file.ext == '.js'){
                    const jsReqObj = require(file.fullPath);
                    const controllersClazz: Array<typeof Controller> =_.filter(jsReqObj, (item)=>(item && Controller.isControllerDClazz(item.prototype)));

                    _.each(controllersClazz,(clazz)=>{

                        try {
                            const controller = new clazz();
                            if(controller.autoRegister){
                                Log.info(file.name+"自动注册");
                                this.registerController(controller);
                            }
                        }catch(err) {
                            Log.info(err)
                        }

                    });

                }
            }
        });

    }



}


//注册策略
export interface IRegisterActionStrategy{
    register(framework:EasyA,action:Action);
}


//使用 express 自带的 next  这个处理能力更强
/*
Running 10s test @ http://localhost:2333/?aaa=11
10 connections

Stat         Avg    Stdev   Max
Latency (ms) 4.67   1.51    33.63
Req/Sec      1943   141.26  2103
Bytes/Sec    561 kB 42.3 kB 608 kB

19k requests in 10s, 5.62 MB read
 */
export class RegisterActionWithExpressNext implements IRegisterActionStrategy{

    register(framework:EasyA,action: Action) {
        const express = framework.express;
        const route = action.associatedProps.routePath;
        const handles = action.associatedProps.handles;
        const firstHandle = handles[0];
        const method = action.method;

        //对第一个
         express[method](route, function (req:any, res, next) {
            const ctx = new EasyACtx(req,res,next);
            ctx.action = action;
            req.EasyARequest = ctx;
             firstHandle.doHandle(ctx); //handle 之间，通过 express 自己的next 来控制流程
        });

        //剩下的
        _.each(_.tail(handles),(handle)=>{
            express[method](route, function (req:any, res, next) {
                const ctx = req.EasyARequest;
                handle.doHandle(ctx);
            });
        });

    }

}

//使用 typescript 的特性
/*
TS
Running 10s test @ http://localhost:2333/?aaa=11
10 connections

Stat         Avg     Stdev   Max
Latency (ms) 8.23    2.01    34.83
Req/Sec      1144.91 59.87   1255
Bytes/Sec    331 kB  19.5 kB 363 kB
11k requests in 10s, 3.31 MB read
 */
export class RegisterActionWithTSAsync implements IRegisterActionStrategy{

    register(framework:EasyA,action: Action) {
        const express = framework.express;

        const handles = action.associatedProps.handles;
        const route = action.associatedProps.routePath;

        express[action.method](route,async function (req:any, res, next) {
            const ctx = new EasyACtx(req,res,function () {
            });
            ctx.action = action;
            req.EasyARequest = ctx;

            for (let i=0,size=handles.length;i<size ;i++) {
                const handle = handles[i];
                await handle.doHandle(ctx);
            }
            req.next();
        });

    }

}




